#include "ringbuf.h"

#include <stdio.h>
#include <stdlib.h>

qc_bool init_ring_buf(PT_RingBuf fd, qc_u32 size){
	if(size == 0){
	   return qc_false; 
	} 
	
	qc_u32 mode = size % 2;
	if(mode != 0){
		size = size + mode;
	}
	
	fd->buf = malloc(size);
	//memset(fd->buf, 0, size);
	fd->capacity = size;
    fd->write_index = fd->read_index = 0;
    
    return qc_true;
}
qc_bool read_bytes(PT_RingBuf fd, char* byte_buf, qc_32 nbytes){
	if(read_able_bytes(fd) < nbytes){
		return qc_false;
	}
	
	qc_u32 c = fd->capacity;
	qc_u32 r = fd->read_index%c;
	qc_32 left = c - r;
	
	if(left >= nbytes){
		memcpy(byte_buf, fd->buf + r, nbytes);
	}else{
		memcpy(byte_buf, fd->buf + r, left);
		memcpy(byte_buf + left, fd->buf, nbytes - left);
	}
	
	fd->read_index += nbytes;
	return qc_true;	
}
qc_bool write_bytes(PT_RingBuf fd, char* byte_buf, qc_32 nbytes){
	if(write_able_bytes(fd) < nbytes){
		return qc_false;
	}
	
	qc_u32 c = fd->capacity;
	qc_u32 w = fd->write_index%c;
	qc_32 left = c - w;
	
	if(left >= nbytes){
		memcpy(fd->buf + w, byte_buf, nbytes);
	}else{
		memcpy(fd->buf + w, byte_buf, left);
		memcpy(fd->buf, byte_buf + left, nbytes - left);
	}
	
    fd->write_index += nbytes;
	return qc_true;
}

inline qc_bool is_empty(PT_RingBuf fd){
	return fd->write_index == fd->read_index;	
}

inline qc_bool is_full(PT_RingBuf fd){
	qc_u32 r = fd->read_index;
	qc_u32 w = fd->write_index;
	qc_u32 c = fd->capacity;
	return (w!=r) && (w%c==r%c);	
}

qc_32 write_able_bytes(PT_RingBuf fd){
	//printf("rIndex=%u, wIndex=%u\n", fd->read_index, fd->write_index);
	if(is_full(fd)){
		return 0;
	}
	
	if(fd->read_index == fd->write_index){
		return fd->capacity;
	}
	
	qc_u32 c = fd->capacity;
	qc_u32 r = fd->read_index%c;
	qc_u32 w = fd->write_index%c;
	
	if(w > r){
		return c - w + r;
	}
	
	return r - w;
}

qc_32 read_able_bytes(PT_RingBuf fd){
	if(is_empty(fd)){
		return 0;
	}
	//printf("r# rindex=%u, windex=%u\n",fd->read_index, fd->write_index);
	return fd->capacity - write_able_bytes(fd);
}

void release(PT_RingBuf fd){
	if(fd){
		if(fd->buf){
			free(fd->buf);
			fd->buf=0;
		}
	}	
}
